#include "gchannel.h"

#include "Log.h"
#include "pfunc.h"
#include "luadisp.h"
#include "business_def.h"

#include <time.h> 
#ifdef __linux__
#include <stdlib.h>
#endif

float  GatherChannel::FLIMIT = float(0.0000001);

GatherChannel::GatherChannel(int gid)
	: ptr_BDef(BusinessDef::getInstance())
{
	init(gid);
}

GatherChannel::~GatherChannel(void)
{
	releaseLua();
}

void GatherChannel::init(int gid)
{
	//获取采集信道属性
	if(!ptr_BDef->getGatherAttsByID(gid,gatheratts))
	{
		CLogger::createInstance()->Log(MsgWarn,
			"GatherChannel(%d) is not map atts config! [%s %s %d]"
			, gid, __FILE__, __FUNCTION__, __LINE__);
	}
	//获取采集信道匹配的协议配置
	if(!ptr_BDef->getProtocolInfoByGID(gid,protodefs))
	{
		CLogger::createInstance()->Log(MsgWarn,
			"GatherChannel(%d) is not map protocol config! [%s %s %d]"
			, gid, __FILE__, __FUNCTION__, __LINE__);
	}
	//读取采集信道的信息点集，重新生成映射关系，方便业务数据快速中转
	std::list<pyfree::PInfo> plist;
	if(ptr_BDef->getPoitInfoByID(gid,plist))
	{
		//建立本采集信道下地址点与编号点映射
		for (std::list<pyfree::PInfo>::iterator it = plist.begin(); it != plist.end(); ++it)
		{
			it->updateTime	= static_cast<unsigned int>(time(NULL));
			it->sendTime	= static_cast<unsigned int>(time(NULL));
			// addr_pid_pinfos[it->addr]	= (*it);
			addr_pid_pinfos[KeyObj_GAddr(it->dev_addr, it->addr)] = (*it);
			pid_addr_pinfos[it->id]		= (*it);
			dev_addrs.insert(it->dev_addr);
		}
	}
	//读取采集信道的计算信息点集，重新生成映射关系，方便业务数据快速中转
	std::list<pyfree::PFuncInfo> fplist;
	if(ptr_BDef->getFPoitInfoByID(gid,fplist))
	{
		//本采集信道下计算点信息映射
		for (std::list<pyfree::PFuncInfo>::iterator it = fplist.begin(); it != fplist.end(); ++it)
		{
			pid_addr_pfinfos[it->id] = (*it);
		}
	}
	//构建信道通信的数据队列
	char buf[128] = {0};
	sprintf(buf,"%s[%d]_read_queue",gatheratts.name.c_str(),gatheratts.id);
	ReadDatas = new QueueData<ChannelCmd>(std::string(buf));	//采集信道读取帧数据
	sprintf(buf,"%s[%d]_write_queue",gatheratts.name.c_str(),gatheratts.id);
	WriteDatas = new QueueData<ChannelCmd>(std::string(buf));	//采集信道写入帧数据
	//
	ToTranDatas = QueueDataSingle<ChannelToTransmit>::getInstance();
	ToTranDatas->setQueueDesc("To_Tran_queue");
	initLua();
	reSetlua();
}

void GatherChannel::initLua()
{
	try
	{
		//协议解析脚本
		error_lua_count = 1;
		luaScript = new luadisp();	
	}
	catch (const std::exception&e)
	{
		releaseLua();
		CLogger::createInstance()->Log(MsgWarn,
			"GatherChannel(%d,%s) init lua fail(%s)! [%s %s %d]"
			, gatheratts.id,gatheratts.name.c_str(), e.what()
			, __FILE__, __FUNCTION__, __LINE__);
		return;
	}
};

void GatherChannel::reSetlua()
{
	if (NULL== luaScript)
	{
		CLogger::createInstance()->Log(MsgWarn,
			"GatherChannel(%d,%s) init lua fail,please check it! [%s %s %d]"
			, gatheratts.id,gatheratts.name.c_str()
			, __FILE__, __FUNCTION__, __LINE__);
		return;
	}
	luaScript->close();
	if (!cmdlist.cmd_totalcall.empty()) 
	{
		cmdlist.cmd_totalcall.clear();
	}
	if (!luaScript->open(protodefs.luafile.c_str()))
	{
		CLogger::createInstance()->Log(MsgWarn,
			"GatherChannel(%d,%s) open lua_script file(%s) fail! [%s %s %d]"
			, gatheratts.id,gatheratts.name.c_str()
			, protodefs.luafile.c_str()
			, __FILE__, __FUNCTION__, __LINE__);
	}
	else {
		std::string _allcall = "";
		std::string _errormsg = "";
		int _type = 0;
		//从脚本获取总召命令集,总召命令可以是针对信道所有信息点,也可以是部分点
		if (luaScript->getTotalCallCMD(_allcall, _errormsg, _type) && !_allcall.empty())
		{
			cmdlist.time_totalcall = static_cast<unsigned long>(clock());
#ifdef __linux__
			cmdlist.time_totalcall = static_cast<unsigned long>(cmdlist.time_totalcall / 1000);
#endif
			std::vector<std::string> _maps;
			if (pyfree::string_divide(_maps, _allcall, ","))
			{
				for (std::vector<std::string>::iterator it = _maps.begin(); it != _maps.end(); ++it)
				{
					switch (_type)//总召指令处置类型
					{
					case 0://nothing do it
					{
						cmdlist.cmd_totalcall.push_back((*it));
					}
					break;
					case 1://hex and CRC
					{
						std::string _cmd = (*it);
						unsigned char buf[256] = { 0 };
						int rlen = pyfree::string2bytes(_cmd.c_str(), buf, static_cast<int>(_cmd.length()));
						unsigned int crc = pyfree::crc16(buf, rlen);
						sprintf((char*)buf, "%s%02X%02X"
							, _cmd.c_str(), (crc & 0XFF), ((crc >> 8) & 0XFF));
						_cmd = std::string((char*)buf);
						cmdlist.cmd_totalcall.push_back(_cmd);
					}
					break;
					case 2://hex to ascii
					{
						char buf[128] = { 0 };
						// int length = static_cast<int>((*it).length());
						int buflen = pyfree::string2bytes((const char*)((*it).c_str())
							, (unsigned char*)buf, static_cast<int>((*it).length()));//hex to ascii
						std::string _cmd = std::string((char*)buf, buflen);
						cmdlist.cmd_totalcall.push_back(_cmd);
					}
					break;
					case 3://hex and CRC, then to ascii 
					{
						std::string _cmd = (*it);
						unsigned char buf[256] = { 0 };
						int rlen = pyfree::string2bytes(_cmd.c_str(), buf, static_cast<int>(_cmd.length()));
						unsigned int crc = pyfree::crc16(buf, rlen);
						sprintf((char*)buf, "%s%02X%02X"
							, _cmd.c_str(), (crc & 0XFF), ((crc >> 8) & 0XFF));
						_cmd = std::string((char*)buf);

						char acsii_buf[128] = { 0 };
						int buflen = pyfree::string2bytes((const char*)(_cmd.c_str()), (unsigned char*)acsii_buf
							, static_cast<int>(_cmd.length()));//hex to ascii
						_cmd = std::string((char*)acsii_buf, buflen);
						cmdlist.cmd_totalcall.push_back(_cmd);
					}
					break;
					default:
					{
						cmdlist.cmd_totalcall.push_back((*it));
					}
					break;
					}
					Print_NOTICE("GatherChannel(%d,%s) add totalcall cmd(%s)\n"
						, gatheratts.id,gatheratts.name.c_str(), (*it).c_str());
				}
			}
		}
		else
		{
			CLogger::createInstance()->Log(MsgWarn,
				"GatherChannel(%d,%s) getTotalCallCMD from lua_script(%s) fail! [%s %s %d]"
				, gatheratts.id,gatheratts.name.c_str()
				, protodefs.luafile.c_str()
				, __FILE__, __FUNCTION__, __LINE__);
		}
	}
};

void GatherChannel::releaseLua()
{
	if (NULL != luaScript) 
	{
		luaScript->close();
		delete luaScript;
		luaScript = NULL;
	}
};

void GatherChannel::pointInitReset()
{
	//采集点状态重置
	for (std::map<KeyObj_GAddr, pyfree::PInfo>::iterator it = addr_pid_pinfos.begin(); it != addr_pid_pinfos.end(); ++it)
	{
		//初始化并上送
		it->second.value = it->second.defvalue;
		setPValue(it->second.id, it->second.type, it->second.defvalue);
	}
}

void GatherChannel::TimeUpState()
{
	//采集点状态
	unsigned int curT = static_cast<unsigned int>(time(NULL));
	for (std::map<KeyObj_GAddr, pyfree::PInfo>::iterator it = addr_pid_pinfos.begin(); it != addr_pid_pinfos.end(); ++it)
	{
		//间隔超timePush秒(默认10)上送
		if ((it->second.sendTime + gatheratts.timePush) < curT)
		{
			it->second.sendTime = curT;
			setPValue(it->second.id, it->second.type, it->second.value);
		}
	}
};


void GatherChannel::msgAnalysis(const std::string up_cmd,std::string down_cmd,unsigned long task_id
		,bool control_flag, unsigned long dev_addr)
{
	std::string recs = "";
	std::string lua_msg = "";
	if (luaScript->getReciveIDVAL(up_cmd.c_str(), recs, lua_msg, down_cmd))
	{
#ifdef DEBUG
		Print_NOTICE("control:%s,ret_cmd:%s,recs:%s\n"
			, down_cmd.c_str(), up_cmd.c_str(), recs.c_str());
#endif 
		if (control_flag) 
		{
			CLogger::createInstance()->Log(MsgInfo
				, "TaskID[%lu] and up_node[1] SerialGChannel::getReciveIDVAL from lua(%s)"
				" for GatherChannel(%d,%s) when control,"
				" deal with the CMD(%s) and it's RETCMD(%s)!"
				" recs(%s), lua_msg(%s)!"
				, task_id
				, protodefs.luafile.c_str()
				, gatheratts.id
				, gatheratts.name.c_str()
				, down_cmd.c_str()
				, up_cmd.c_str()
				, recs.c_str()
				, lua_msg.c_str());
		}
		std::map<int, float> pf_mapVals;//用于计算点公式计算
		std::vector<std::string> val_maps;
		if (pyfree::string_divide(val_maps, recs, ";"))
		{
			int p_id = 0;
			float p_val = 0.0;
			for (size_t i = 0, mSize = val_maps.size(); i < mSize; ++i)
			{
				std::vector<std::string> val_map;
				if (pyfree::string_divide(val_map, val_maps[i], ",") && 2 == val_map.size())
				{
					p_id  = atoi(val_map[0].c_str());
					p_val = static_cast<float>(atoi(val_map[1].c_str()));
					pf_mapVals[p_id] = p_val;
					setValue(p_id, p_val, task_id,dev_addr);
				}
			}
		}
		setPFuncValue(pf_mapVals);
	}
	else {
		CLogger::createInstance()->Log(MsgWarn
			, "TaskID[%lu] and up_node[1-1] GatherChannel(%d,%s) getReciveIDVAL from lua(%s) is error,"
			" cann't deal with the CMD(%s) and it's RETCMD(%s)!"
			" recs(%s), error_lua_msg(%s)!"
			, task_id
			, gatheratts.id
			, gatheratts.name.c_str()
			, protodefs.luafile.c_str()
			, down_cmd.c_str()
			, up_cmd.c_str()
			, recs.c_str()
			, lua_msg.c_str());
		error_lua_count++;
		if (error_lua_count >= error_lua_max) 
		{
			error_lua_count = 1;
			reSetlua();//重载脚本
		}
	}
}

void GatherChannel::setValue(int addr, float val, unsigned long task_id, unsigned long dev_addr)
{
	//查找与信息地址匹配的信息编号
	std::map<KeyObj_GAddr, pyfree::PInfo>::iterator it = addr_pid_pinfos.find(KeyObj_GAddr(dev_addr,addr));
	if (it != addr_pid_pinfos.end())
	{
		float m_val_ = val;
		if (it->second.type == pyfree::OnYX)
		{
			m_val_ = m_val_ > 0 ? float(1) : float(0);
		}
		it->second.updateTime = static_cast<unsigned int>(time(NULL));
		//变化上送或间隔2秒上送
		bool changef = abs(it->second.value - m_val_) > FLIMIT;
		if (changef|| (it->second.sendTime + it->second.upInterval) < it->second.updateTime)
		{
			it->second.sendTime = it->second.updateTime;
			setPValue(it->second.id, it->second.type, m_val_, changef, it->second.logFlag?task_id:0);
		}
		it->second.value = m_val_;//冗余记录
	}
	else {
		if(addr>0)
		{
			CLogger::createInstance()->Log(MsgWarn,
				"TaskID[%lu] and up_node[1-2] GatherChannel(%d,%s) setValue when addr_pid_pinfos.find(%lu,%d) fail and val(%f)"
				" . [%s %s %d]"
				, task_id
				, gatheratts.id
				, gatheratts.name.c_str()
				, dev_addr,addr,val
				, __FILE__, __FUNCTION__, __LINE__);
		}
		//如果需要通信状态信息,也需要配置信息点,不在默认转发
		// else{
		// 	setPValue(addr,pyfree::ON_YX,val,changef,task_id);
		// }
	}
};

//计算公式库
#include "muParser.h"
using namespace mu;

void GatherChannel::setPFuncValue(std::map<int, float> _mapVals)
{
	if(_mapVals.empty())
	{
		return;
	}
	if (pid_addr_pfinfos.empty())
	{
		return;
	}
	for (std::map<int, pyfree::PFuncInfo>::iterator it = pid_addr_pfinfos.begin();
		it != pid_addr_pfinfos.end(); ++it)
	{
		//根据计算公式计算信息点数值
		try {
			Parser p;
			unsigned int aSize = static_cast<unsigned int>(it->second.args.size());
			double *_dval = new double[aSize];
			bool argF = true;
			for (unsigned int i = 0; i < aSize; ++i)
			{
				std::map<int, float>::iterator itv = _mapVals.find(it->second.args[i].paddr);
				if (itv != _mapVals.end())
				{
					_dval[i] = static_cast<double>(itv->second);
					p.DefineVar(it->second.args[i].name, &_dval[i]);
				}
				else {
					argF = false;
					break;
				}
			}
			if (argF)
			{
				p.SetExpr(it->second.expr);
				float _val_ = static_cast<float>(static_cast<double>(p.Eval()));
				it->second.updateTime = static_cast<unsigned int>(time(NULL));
				//变化上送或间隔2秒上送
				bool changef = abs(it->second.value - _val_) > FLIMIT ? true : false;
				if (changef || (it->second.sendTime + 1) < it->second.updateTime)
				{
					it->second.sendTime = it->second.updateTime;
					setPValue(it->first, it->second.type, _val_, changef);
				}
				it->second.value = _val_;
			}
			delete[] _dval;
			_dval = NULL;
		}
		catch (Parser::exception_type &e)
		{
			std::cout << e.GetMsg() << std::endl;
			CLogger::createInstance()->Log(MsgWarn,
				"GatherChannel(%d,%s) setPFuncValue exception(%s),[%s %s %d]!"
				, gatheratts.id,gatheratts.name.c_str()
				, e.GetMsg().c_str()
				, __FILE__, __FUNCTION__, __LINE__);
		}
	}
};

void GatherChannel::setPValue(int pid, pyfree::PType type, float val, bool changeUp, unsigned long task_id)
{
	//查找与信息编号匹配的转发编号
	pyfree::PTo _pto;
	if (ptr_BDef->getPTO(gatheratts.id, pid, type, _pto))
	{
		ChannelToTransmit _wd(_pto.ptype, _pto.pid, val, changeUp, task_id);
		ToTranDatas->add(_wd);
		if (changeUp&&task_id>0)
		{
			CLogger::createInstance()->Log(MsgInfo,
				"TaskID[%lu] and up_node[2] GatherChannel(%d,%s) setPValue"
				",pid(%d),ptype(%d),val(%.2f) "
				",and map pID(%d),pType(%d)!"
				, task_id
				, gatheratts.id,gatheratts.name.c_str()
				, pid, static_cast<int>(type), val
				, _pto.pid, static_cast<int>(_pto.ptype));
		}
	}
	else {
		if (pid > 0 && changeUp) 
		{
			CLogger::createInstance()->Log(MsgWarn,
				"TaskID[%lu] and up_node[2-1] GatherChannel(%d,%s) setPValue(%d,%d,%.2f) "
				"but getPTO fail. [%s %s %d]"
				, task_id
				, gatheratts.id,gatheratts.name.c_str()
				, pid, static_cast<int>(type), val
				, __FILE__, __FUNCTION__, __LINE__);
		}
		//如果需要通信连接状态,也需要配置信息点,不在默认转发
		// else{
		// 	ChannelToTransmit _wd(type,pid, val, changeUp, task_id);
		// 	ToTranDatas->add(_wd);
		// }
	}
}

bool GatherChannel::getCmd(int exetype, int type, int pid, float _val
	, std::string &cmd, int &checktype, unsigned long &dev_addr,unsigned long task_id)
{
	std::map<int, pyfree::PInfo>::iterator it = pid_addr_pinfos.find(pid);
	if (it == pid_addr_pinfos.end())
	{
		return false;
	}
	dev_addr = it->second.dev_addr;
	// printf("--------------------GatherChannel::getCmd-%lu-----------------------\n",dev_addr);
	CLogger::createInstance()->Log(MsgInfo,
		"TaskID[%lu] and down_node[4] downControl, time(%s)"
		", GatherChannel(%d,%s), exeType(%d),pID(%d),pType(%d),val(%.3f)"
		, task_id, pyfree::getCurrentTime().c_str()
		, gatheratts.id,gatheratts.name.c_str()
		, static_cast<int>(exetype), pid, static_cast<int>(type), _val);
	if (pid < 0)
	{
		;//
	}
	bool getCmdF = false;
	std::string _errormsg = "";
	if (luaScript->getDownControl(exetype, type, it->second.addr
		, static_cast<int>(_val), cmd, checktype, _errormsg, static_cast<unsigned int>(task_id))
		&& !cmd.empty())
	{
		CLogger::createInstance()->Log(MsgInfo,
			"TaskID[%lu] and down_node[5] downControl,time(%s)"
			", GatherChannel(%d,%s), getDownControl success, CMD(%s)"
			, task_id, pyfree::getCurrentTime().c_str()
			, gatheratts.id,gatheratts.name.c_str()
			, cmd.c_str());
		switch (checktype)
		{
		case 1://CRC
		{
			unsigned char buf[256] = { 0 };
			int rlen = pyfree::string2bytes(cmd.c_str(), buf, static_cast<int>(cmd.length()));
			unsigned int crc = pyfree::crc16(buf, rlen);
			sprintf((char*)buf, "%s%02X%02X", cmd.c_str(), (crc & 0XFF), ((crc >> 8) & 0XFF));
			cmd = std::string((char*)buf);
		}
		break;
		case 2://hex to ascii
		{
			unsigned char buf[256] = { 0 };
			int len = pyfree::string2bytes(cmd.c_str(), buf, static_cast<int>(cmd.length()));
			//for (int j = 0; j < len; j++) {
			//	printf("%02X", buf[j]);
			//}
			//printf("\n");
			cmd = std::string((char*)buf, len);
		}
		break;
		case 3://hex and crc，then to ascii
		{
			unsigned char buf[256] = { 0 };
			int rlen = pyfree::string2bytes(cmd.c_str(), buf, static_cast<int>(cmd.length()));
			unsigned int crc = pyfree::crc16(buf, rlen);
			sprintf((char*)buf, "%s%02X%02X", cmd.c_str(), (crc & 0XFF), ((crc >> 8) & 0XFF));
			cmd = std::string((char*)buf);

			char acsii_buf[128] = { 0 };
			int buflen = pyfree::string2bytes((const char*)(cmd.c_str()), (unsigned char*)acsii_buf
				, static_cast<int>(cmd.length()));//hex to ascii
			cmd = std::string((char*)acsii_buf, buflen);
		}
		break;
		default:
			break;
		}
		getCmdF = true;
		if (1 == protodefs.ykSetVal && 1 == type)//遥控直接设值,不等返回
		{
			setValue(it->second.addr, _val, task_id,dev_addr);
			//setPValue(pid, OnYX, _val, true, task_id);//setValue已经有setPValue的判定与设值
		}
	}
	else
	{
		CLogger::createInstance()->Log(MsgWarn,
			"TaskID[%lu] and down_node[5-1] downControl,time(%s)"
			", GatherChannel(%d,%s), exeType(%d),pID(%d),pType(%d),val(%.3f)"
			",getDownControl Error"
			, task_id, pyfree::getCurrentTime().c_str()
			, gatheratts.id,gatheratts.name.c_str()
			, static_cast<int>(exetype), pid, static_cast<int>(type), _val);
		error_lua_count++;
		if (error_lua_count >= error_lua_max) 
		{
			error_lua_count = 1;
			reSetlua();
		}
	}
	return getCmdF;
}
